package com.shensi.common.core.interceptor;

import com.alibaba.fastjson.JSON;
import com.shensi.common.core.constant.GlobalConstant;
import com.shensi.common.core.constant.ServiceContext;
import com.shensi.common.core.constant.ServiceContextHolder;
import com.shensi.common.core.domain.model.LoginUser;
import com.shensi.common.core.utils.SecurityUtils;
import com.shensi.common.core.utils.StringUtils;
import com.shensi.common.core.utils.uuid.UUID;
import feign.RequestInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;

/**
 * <p>
 * 服务上下文拦截器
 * </p>
 *
 * @author zph
 * @since 2024-01-29
 */
@Configuration
public class GlobalContextInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果不是映射conrtoller中的方法，直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        // 如果是方法探测，直接通过
        if (HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod())) {
            //OPTIONS请求不拦截
            return true;
        }
        if (!"REQUEST".equals(request.getDispatcherType().name())) {
            //不是request类型目前不处理
            return true;
        }
        String requestId = request.getHeader(GlobalConstant.HEADER_KEY_REQUEST_ID);
        String tenantId = request.getHeader(GlobalConstant.HEADER_KEY_TENANT_ID);
        String instanceId = request.getHeader(GlobalConstant.HEADER_KEY_INSTANCE_ID);
        String applicationId = request.getHeader(GlobalConstant.HEADER_KEY_APPLICATION_ID);
        String userId = request.getHeader(GlobalConstant.HEADER_KEY_USER_ID);
        String loginName = request.getHeader(GlobalConstant.HEADER_KEY_LOGIN_NAME);

        ServiceContext serviceContext = ServiceContextHolder.getContext();
        serviceContext.setRequestId(org.apache.commons.lang3.StringUtils.isNoneBlank(requestId) ? requestId : UUID.fastUUID().toString());
        MDC.put(GlobalConstant.HEADER_KEY_REQUEST_ID, serviceContext.getRequestId());
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(tenantId)) {
            serviceContext.setTenantId(tenantId);
        }
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(instanceId)) {
            serviceContext.setInstanceId(instanceId);
        }
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(applicationId)) {
            serviceContext.setApplicationId(applicationId);
        }
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(userId)) {
            serviceContext.setUserId(userId);
        }
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(loginName)) {
            serviceContext.setLoginName(loginName);
        }

        Enumeration<String> headerNames = request.getHeaderNames();
        String key;
        while (headerNames.hasMoreElements()) {
            key = headerNames.nextElement();
            if (key.startsWith(ServiceContext.EXT_KEY_PREFIX)) {
                String value = request.getHeader(key);
                if (org.apache.commons.lang3.StringUtils.isNoneBlank(value)) {
                    serviceContext.putExtValue(key, value);
                }
            }
        }

        ServiceContextHolder.set(serviceContext);
        String userInfo = request.getHeader(GlobalConstant.HEADER_KEY_USER_INFO);
        if (StringUtils.isNoneBlank(userInfo)) {
            LoginUser loginUser = JSON.parseObject(userInfo, LoginUser.class);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null);
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            return true;
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除上下文
        SecurityContextHolder.getContext().setAuthentication(null);
        MDC.clear();
    }
}
